//有一个 m × n 的矩形岛屿，与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界，而 “大西洋” 处于大陆的右边界和下边界。 
//
// 这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heights ， heights[r][c] 表示坐标 (r, c) 上
//单元格 高于海平面的高度 。 
//
// 岛上雨水较多，如果相邻单元格的高度 小于或等于 当前单元格的高度，雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。 
//
// 返回网格坐标 result 的 2D 列表 ，其中 result[i] = [ri, ci] 表示雨水从单元格 (ri, ci) 流动 既可流向太平洋也可
//流向大西洋 。 
//
// 
//
// 示例 1： 
//
// 
//
// 
//输入: heights = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]
//输出: [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]
// 
//
// 示例 2： 
//
// 
//输入: heights = [[2,1],[1,2]]
//输出: [[0,0],[0,1],[1,0],[1,1]]
// 
//
// 
//
// 提示： 
//
// 
// m == heights.length 
// n == heights[r].length 
// 1 <= m, n <= 200 
// 0 <= heights[r][c] <= 10⁵ 
// 
// Related Topics深度优先搜索 | 广度优先搜索 | 数组 | 矩阵 
//
// 👍 526, 👎 0 
//
//
//
//

package leetcode.editor.cn;


import javafx.util.Pair;

import java.util.*;

class PacificAtlanticWaterFlow {
    public static void main(String[] args) {
        Solution solution = new PacificAtlanticWaterFlow().new Solution();
    }

    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        // DFS:分别求出能流向大西洋和太平洋的陆地，再求交集就可以获得
        public List<List<Integer>> pacificAtlantic(int[][] heights) {
            int m = heights.length, n = heights[0].length;
            boolean[][] pacific = new boolean[m][n]; // // 记录能流向太平洋
            boolean[][] atlantic = new boolean[m][n]; // 记录能流向大西洋

            for (int i = 0; i < m; i++) {
                // dfs(heights, i, n - 1, 0, atlantic);
                bfs(heights, i, n - 1, atlantic);
            }

            for (int i = 0; i < n; i++) {
                // dfs(heights, m - 1, i, 0, atlantic);
                bfs(heights, m - 1, i, atlantic);
            }

            for (int i = 0; i < m; i++) {
                // dfs(heights, i, 0, 0, pacific);
                bfs(heights, i, 0, pacific);
            }

            for (int i = 0; i < n; i++) {
                // dfs(heights, 0, i, 0, pacific);
                bfs(heights, 0, i, pacific);
            }

            // 求出流向大西洋和太平洋的陆地
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    if (pacific[i][j] && atlantic[i][j]) res.add(Arrays.asList(i, j));
                }
            }

            return res;
        }

        List<List<Integer>> res = new LinkedList<>();

        public void dfs(int[][] heights, int i, int j, int val, boolean[][] ocean) {
            if (i < 0 || j < 0 || i >= heights.length || j >= heights[0].length || heights[i][j] < val || ocean[i][j])
                return;
            val = heights[i][j];
            ocean[i][j] = true;
            dfs(heights, i + 1, j, val, ocean);
            dfs(heights, i - 1, j, val, ocean);
            dfs(heights, i, j + 1, val, ocean);
            dfs(heights, i, j - 1, val, ocean);
        }

        // BFS思路和DFS一致
        public void bfs(int[][] heights, int i, int j, boolean[][] ocean) {
            if (ocean[i][j]) return;
            ocean[i][j] = true;
            int[][] dirs = new int[][]{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
            Queue<int[]> queue = new LinkedList<>();
            queue.offer(new int[]{i, j});
            while (!queue.isEmpty()) {
                int[] poll = queue.poll();
                int x = poll[0], y = poll[1];
                for (int[] dir : dirs) {
                    int x1 = x + dir[0];
                    int y1 = y + dir[1];
                    if (x1 < 0 || y1 < 0 || x1 >= heights.length || y1 >= heights[0].length || heights[x1][y1] < heights[x][y] || ocean[x1][y1])
                        continue;
                    ocean[x1][y1] = true;
                    queue.offer(new int[]{x1, y1});
                }
            }
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}
